using System;
using Irc.Events;
using Irc.Objects;
using System.Reflection;
using System.Collections.Generic;

namespace Irc.Net
{
	/// <summary>
	/// Description of CommandManager.
	/// </summary>
	public class CommandManager
	{
		private struct Command
		{
			public Assembly CommandOwner;
			public IrcCommand CommandHandler;
		}
		private static CommandManager instance = new CommandManager();
		public static CommandManager Instance
		{
			get { return instance; }
		}
		private Dictionary<string,Command> commands = new Dictionary<string,Command>();
		public string[] Commands
		{
			get
			{
				string[] actualCommands = new string[commands.Keys.Count];
				commands.Keys.CopyTo(actualCommands, 0);
				return actualCommands;
			}
		}

		private CommandManager(){}

		public void RegisterCommand(string command, IrcCommand handler)
		{
			if(commands.ContainsKey(command))
				throw new CommandExistsException(command);
			else
			{
				Command c = new Command();
				c.CommandHandler = handler;
				c.CommandOwner = new System.Diagnostics.StackTrace(false).GetFrame(1).GetMethod().DeclaringType.Assembly;
				commands.Add(command, c);
			}
		}
		public bool CommandExists(string command)
		{
			return commands.ContainsKey(command);
		}
		public void RemoveCommand(string command)
		{
			Assembly caller = new System.Diagnostics.StackTrace(false).GetFrame(1).GetMethod().DeclaringType.Assembly;
			if(caller != commands[command].CommandOwner && caller != Assembly.GetAssembly(typeof(Main)))
				throw new UnauthorizedAccessException();
			else
				commands.Remove(command);
		}
		public bool Raise(Client client, Target target, string command, string[] parameters)
		{
			if(!commands.ContainsKey(command))
				return false;
			Assembly caller = new System.Diagnostics.StackTrace(false).GetFrame(1).GetMethod().DeclaringType.Assembly;
			if(caller != commands[command].CommandOwner && caller != Assembly.GetAssembly(typeof(Main)))
				throw new UnauthorizedAccessException();
			else
				commands[command].CommandHandler.Invoke(client, target, parameters);
			return true;
		}
	}
	public delegate void IrcCommand(Client clientObject, Target target, string[] parameters);
	public class CommandExistsException : Exception
	{
		private string commandName;
		public string CommandName { get { return commandName; } }
		public CommandExistsException(string commandName) {this.commandName = commandName;}
	}
}
